﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
using LevelEditor.Objects.Tiles;
using LevelEditor.Objects;
using LevelEditor.Objects.Waypoints;
using LevelEditor.Components.Layers;
using LevelEditor.Objects.Layers;
using LevelEditor.Components.Waypoints;
using LevelEditor.Util;
using Microsoft.VisualBasic.PowerPacks;
using LevelEditor.App;

namespace LevelEditor.Components
{
    public class LevelEditorStage : Stage
    {
        private LevelEditor editor;
        private LayerItem gridToDraw;
        private WaypointsPanel waypointPanel; 
        private Timer timer;

        private ShapeContainer shapeContainer;
        private LineShape link;

        public LevelEditorStage()
            : base()
        {
            this.DragDrop += LevelEditor_DragDrop;
            this.DragEnter += LevelEditor_DragEnter;
            this.AllowDrop = true;
            this.AutoScroll = true;

            this.timer = new Timer();
            this.timer.Enabled = true;
            this.timer.Interval = 200;
            this.timer.Tick += timer_Tick;

            this.waypointPanel = new WaypointsPanel();
            this.waypointPanel.Width = this.Width;
            this.waypointPanel.Height = this.Height;
            this.waypointPanel.Location = this.Location;

            shapeContainer = ContainerDefault();
            link = new LineShape();
            link.BorderWidth = 5;

            shapeContainer.Shapes.Add(link);
            
            this.Controls.Add(waypointPanel);
            this.Controls.Add(shapeContainer);
            
            StopEdittingWaypoints();
        }

        private ShapeContainer ContainerDefault()
        {
            ShapeContainer sc = new ShapeContainer();
            sc.Top = 20;
            sc.Left = this.Left;
            return sc;
        }

        void timer_Tick(object sender, EventArgs e)
        {
            ClearGraphics();

            waypointPanel.DrawWaypoints();
            DrawRectangleMark();
            DrawGrid();
            PaintLinks();
            
        }

        protected override void ZoomPanel_MouseWheel(object sender, MouseEventArgs e)
        {
            base.ZoomPanel_MouseWheel(sender, e);

            if (gridToDraw == null) return;

            this.AutoScrollMinSize = new Size((int)(gridToDraw.TileWidth * (gridToDraw.Cols - 1) * this.CurrentZoom), (int)(gridToDraw.TileWidth * (gridToDraw.Cols - 1) * this.CurrentZoom));
        }
        
        public void DrawLayerGrid(LayerItem item)
        {
            this.AutoScrollMinSize = new Size((int)(item.TileWidth * (item.Cols - 1) * this.CurrentZoom), (int)(item.TileWidth * (item.Cols - 1) * this.CurrentZoom));

            if (gridToDraw != null) gridToDraw.ShowingGrid = false;

            this.gridToDraw = item;
            this.waypointPanel.Width = item.TileWidth * (item.Cols - 1);
            this.waypointPanel.Height = item.TileHeight * (item.Rows - 1);
        }

        private void DrawGrid()
        {
            if (gridToDraw == null) return;
            Pen pen = new Pen(Color.Black);
            Graphics g = this.CreateGraphics();
            Point p1 = new Point(), p2 = new Point();

            p2.Y = (int)((gridToDraw.TileHeight * gridToDraw.Rows) * this.CurrentZoom);
            for (int k = 0; k < gridToDraw.Cols; k++)
            {
                p1.X = this.AutoScrollPosition.X + (int)((gridToDraw.TileWidth * this.CurrentZoom) * k);
                p1.Y = 0;
                p2.X = this.AutoScrollPosition.X + (int)((gridToDraw.TileWidth * this.CurrentZoom) * k);

                g.DrawLine(pen, p1, p2);
            }

            p2.X = (int)((gridToDraw.TileWidth * gridToDraw.Cols) * this.CurrentZoom);
            for (int k = 0; k < gridToDraw.Rows; k++)
            {
                p1.X = 0;
                p1.Y = this.AutoScrollPosition.Y + (int)((gridToDraw.TileHeight * this.CurrentZoom) * k);
                p2.Y = this.AutoScrollPosition.Y + (int)((gridToDraw.TileHeight * this.CurrentZoom) * k);

                g.DrawLine(pen, p1, p2);
            }

            pen.Dispose();
            g.Dispose();
        }

        private void DrawRectangleMark()
        {
            if (Tile.CurrentSelectedTile == null) return;
            if (!Tile.CurrentSelectedTile.IsDragging) return;

            int hScrollValue = 0;
            int vScrollValue = 0;

            Point mousePosition = PointToClient(Cursor.Position);

            int tileWidth = (int)(Tile.CurrentSelectedTile.MyLayer.TileWidth * CurrentZoom);
            int tileHeight = (int)(Tile.CurrentSelectedTile.MyLayer.TileHeight * CurrentZoom);

            int col = (int)(mousePosition.X / tileWidth);
            int row = (int)(mousePosition.Y / tileHeight);

            if (this.AutoScrollPosition.Y % tileHeight != 0)
            {
                int legalValue = (int)Math.Abs(Math.Ceiling(this.AutoScrollPosition.Y / (float)tileHeight) * tileHeight);
                vScrollValue = (legalValue + this.AutoScrollPosition.Y) * -1; // autoscrollposition is < 0
            }

            if (this.AutoScrollPosition.X % tileWidth != 0)
            {
                int legalValue = (int)Math.Abs(Math.Ceiling(this.AutoScrollPosition.X / (float)tileWidth) * tileWidth);
                hScrollValue = (legalValue + this.AutoScrollPosition.X) * -1;
            }

            Point p = new Point((col * tileWidth) - hScrollValue, (row * tileHeight) - vScrollValue);

            Rectangle dropRectangle = new Rectangle(p, new Size(tileWidth, tileHeight));

            RectangleDrawer.Instance().Draw(dropRectangle,
                this, Color.FromArgb(150, Color.SkyBlue));
        }

        public bool EditWaypoints()
        {
            if (waypointPanel.Enable())
            {
                waypointPanel.SetEdittingtCharacter((Character)Tile.CurrentSelectedTile);
                return true;
            }

            return false;
        }

        public void ShowWaypoints(WaypointsCollection waypointsCollection)
        {
            waypointPanel.ShowWaypoints(waypointsCollection);

        }

        public void StopShowingWaypoints()
        {
            if (!waypointPanel.IsShowingWaypoints) return;

            waypointPanel.StopShowingWaypoints();
        }

        public void StopEdittingWaypoints()
        {
            waypointPanel.Disable();
        }

        public bool IsEdittingWaypoints()
        {
            return waypointPanel.Enabled;
        }

        public void HideGrid()
        {
            gridToDraw = null;
            Graphics g = this.CreateGraphics();
            g.Clear(Color.White);
        }

        public void SetEditor(LevelEditor editor)
        {
            this.editor = editor;
        }

        protected override void LevelEditor_DragDrop(object sender, DragEventArgs e)
        {
            Point localPosition = PointToClient(Cursor.Position);

            Tile tile = (Tile)e.Data.GetData(typeof(Tile));
            if (tile == null)
                tile = (Tile)e.Data.GetData(typeof(Character));

            if (tile == null)
                tile = (Tile)e.Data.GetData(typeof(Item));

            if (tile == null)
                tile = (Tile)e.Data.GetData(typeof(Door));

            if (tile == null)
                tile = (Tile)e.Data.GetData(typeof(CTile));

            if (tile == null) return;

            if (this.Controls.Contains(tile)) return;

            if (!editor.layerPanel1.HasLayer())
            {
                NewLayer newLayerDialog = new NewLayer(editor);
                DialogResult result = newLayerDialog.ShowDialog();
                if (result == DialogResult.OK)
                {
                    editor.layerPanel1.NewLayer(newLayerDialog.getLayerName(), newLayerDialog.getCols(), 
                        newLayerDialog.getRows(), newLayerDialog.getTileWidth(), newLayerDialog.getTileHeight());
                    editor.layerPanel1.SelectLayer((LayerItem)editor.layerPanel1.Controls[0]);
                }
                else return;
            }

            if (tile.Width > LayerPanel.CurrentLayer.TileWidth || tile.Height > LayerPanel.CurrentLayer.TileHeight)
            {
                if (ErrorController.ShowYesNoError(ErrorController.LevelEditorError.TILE_BIGGER) == DialogResult.No)
                    return;
            }else if (tile.Width < LayerPanel.CurrentLayer.TileWidth || tile.Height < LayerPanel.CurrentLayer.TileHeight)
                if (ErrorController.ShowYesNoError(ErrorController.LevelEditorError.TILE_SMALLER) == DialogResult.No)
                    return;
            
            tile.Father = editor.libraryPanel.CurrentSelectedItem;
            tile.Size = new Size((int)(tile.Image.Width * CurrentZoom), (int)(tile.Image.Height * CurrentZoom));

            int row = localPosition.X / LayerPanel.CurrentLayer.TileWidth;
            int col = localPosition.Y / LayerPanel.CurrentLayer.TileHeight;

            if (LayerPanel.CurrentLayer != null)
            {
                tile.Location = new Point(row * LayerPanel.CurrentLayer.TileWidth,
                    col * LayerPanel.CurrentLayer.TileHeight);
            }
            this.Controls.Add(tile);

            editor.libraryPanel.CurrentSelectedItem.AddIntance(tile);

            LayerPanel.CurrentLayer.myLayer.Add(tile);

            tile.MyLayer = LayerPanel.CurrentLayer;

            editor.layerPanel1.UpdateIndexes();
        }
        
        protected override void OnControlAdded(ControlEventArgs e)
        {
            base.OnControlAdded(e);
            if ((e.Control as Tile) == null) return;
            (e.Control as Tile).ID = this.Controls.IndexOf((e.Control as Tile));
        }

        private void PaintLinks()
        {
            if (!LevelEditor.IsCreatingConnectors || Tile.CurrentSelectedTile == null)
            {
                link.Visible = false;
                return;
            }

            foreach (Control c in Controls)
            {

                if ((c is Tile) && (c as Tile) == Tile.CurrentSelectedTile)
                {
                    link.X1 = (c as Tile).Location.X;
                    link.Y1 = (c as Tile).Location.Y;
                    link.X2 = PointToClient(Cursor.Position).X;
                    link.Y2 = PointToClient(Cursor.Position).Y;
                    link.Visible = true;
                }

            }
        }

        public Tile GetTileInControls(Tile t2)
        {
            if (t2.ID == -1)
            {
                MessageBox.Show("-1");
                return null;
            }

            foreach (Control c in this.Controls)
            {
                if ((c as Tile) == null) continue;

                if ((c as Tile).ID == t2.ID) return (c as Tile);
            }
            return null;
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (!IsEdittingWaypoints() && !WaypointsConfiguration.IsCreatingWaypointConfiguration)
            {
                if (Tile.CurrentSelectedTile != null)
                    Tile.CurrentSelectedTile.Deselect();
            }
            base.OnMouseDown(e);
        }
    }
}
